//! 泛微OA的API封装
//!
//! 简单的划分类型，封装原始的api
//!
//! Session trait 需要实现request请求头的管理。
//!

use reqwest::{Client, Error as ReqErr};

use crate::{
    models::{
        auth_response::{RegisterToken, Token},
        workflow_request::ToDoListRequest,
        workflow_response::{RequestLog, RequestResponse, ToDoListResponseList},
    },
    uri::{generate_uri, OaPath},
};

/// 通过两个通用函数，获取reqwest::client 和 域名或者ip
pub trait Session {
    fn cli(&self) -> Client;
    /// http/https结构的uri。如http://127.0.0.1/。
    fn base_uri(&self) -> String;
}

/// OA 认证API组
///
/// 首先需要注册，获取到secret和spk，再加密secret 获取token。
pub struct OaAuthApi;

impl OaAuthApi {
    /// 注册接口
    ///
    /// 通过该接口获取secret和spk
    pub async fn register_token(s: &impl Session) -> Result<RegisterToken, ReqErr> {
        s.cli()
            .post(generate_uri(
                s.base_uri().as_mut().to_string(),
                OaPath::RegisterToken,
            ))
            .send()
            .await?
            .json::<RegisterToken>()
            .await
    }

    /// 注册token
    ///
    /// 通过spk加密的secret获取token。
    pub async fn token(s: &impl Session) -> Result<Token, ReqErr> {
        s.cli()
            .post(generate_uri(
                s.base_uri().as_mut().to_string(),
                OaPath::Token,
            ))
            .send()
            .await?
            .json::<Token>()
            .await
    }
}

/// 流程类接口
pub struct WorkFlow;

impl WorkFlow {
    /// 获取流程代办列表
    pub async fn todo_list(
        s: &impl Session,
        c: Option<ToDoListRequest>,
    ) -> Result<ToDoListResponseList, ReqErr> {
        let cli = s.cli().post(generate_uri(
            s.base_uri().as_mut().to_string(),
            OaPath::ToDoWorkflowRequestList,
        ));

        // if let Some(con) = c {
        //     cli.json(&con);
        // };

        let cli = match c {
            Some(con) => cli.json(&con),
            None => cli,
        };

        cli.send().await?.json::<ToDoListResponseList>().await
    }

    /// 根据requestId获取流程的详细信息。
    pub async fn workflow_request(
        s: &impl Session,
        request_id: String,
    ) -> Result<RequestResponse, ReqErr> {
        s.cli()
            .get(generate_uri(
                s.base_uri().as_mut().to_string(),
                OaPath::WorkflowRequest,
            ))
            .query(&[("requestId", request_id)])
            .send()
            .await?
            .json::<RequestResponse>()
            .await
    }

    /// 获取流程意见
    ///
    pub async fn request_log(
        s: &impl Session,
        req_id: String,
        page_size: Option<u32>,
        page_number: Option<u32>,
    ) -> Result<RequestLog, ReqErr> {
        let cli = s.cli().get(generate_uri(
            s.base_uri().as_mut().to_string(),
            OaPath::WorkflowRequestLog,
        ));

        let cli = match page_size {
            Some(ps) => cli.query(&[("pageSize", ps)]),
            None => cli,
        };

        let cli = match page_number {
            Some(ps) => cli.query(&[("pageSize", ps)]),
            None => cli,
        };

        cli.query(&[("requestId", req_id)])
            .send()
            .await?
            .json::<RequestLog>()
            .await
    }
}
